package com.xsf.jieyou.business.controller;

import com.xsf.jieyou.business.BusinessException;
import com.xsf.jieyou.business.common.dto.ResponseResult;
import com.xsf.jieyou.business.common.dto.ResponseStatus;
import com.xsf.jieyou.business.dto.LoginInfo;
import com.xsf.jieyou.business.dto.LoginParam;
import com.xsf.jieyou.business.feign.api.ProfileFeign;
import com.xsf.jieyou.business.service.LoginServiceImpl;
import com.xsf.jieyou.commons.utils.MapperUtils;
import com.xsf.jieyou.commons.utils.UserAgentUtils;
import com.xsf.jieyou.provider.api.ProviderTbUserService;
import com.xsf.jieyou.provider.domain.TbUser;
import com.xsf.jieyou.provider.domain.TbUserLog;
import eu.bitwalker.useragentutils.Browser;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Collection;
import java.util.Date;

/**
 * 登录服务 业务控制层。
 *
 * @author xsf
 * @version v1.0.0
 * @date 2019/11/15 0015 4:35
 * @see com.xsf.jieyou.business.controller
 **/
@RestController
@RequestMapping(value = "/user")
@RefreshScope
@Slf4j
public class LoginController {
    /**
     * 帐号封停：0
     */
    private static final Integer BAN_ACCOUNT_FLAG = 0;
    /**
     * 帐号解封：1
     */
    private static final Integer UNBAN_ACCOUNT_FLAG = 1;

    @Value("${oauth2.client_id}")
    private String oauth2ClientId;

    @Resource
    private ProfileFeign profileFeign;
    @Resource
    public TokenStore tokenStore;
    @Resource
    private LoginServiceImpl loginServiceImpl;
    @Reference(version = "1.0.0")
    private ProviderTbUserService providerTbUserService;
    // @Reference(version = "1.0.0")
    // private MessageService messageService;

    /**
     * 用户登录
     *
     * @param loginParam {@link LoginParam}
     * @return {@link ResponseResult}
     */
    @PostMapping("/login")
    public ResponseResult<?> login(@RequestBody LoginParam loginParam, HttpServletRequest request) {
        // 3、RocketMq异步新增用户操作日志
        // this.sendTbUserLog(userDetails.getUsername(), request, "用户登录");

        return this.loginServiceImpl.login(loginParam);
    }

    /**
     * 注销登录
     *
     * @param request {@link HttpServletRequest}
     * @return {@link ResponseResult}
     */
    @PreAuthorize("hasAuthority('USER')")
    @PostMapping("/logout")
    public ResponseResult<Void> logout(HttpServletRequest request) {
        // 从请求头中获取 token
        // authorization: Bearer 1ce48cb6-5678-489f-975a-80e8c43d1f56
        String token = request.getHeader("authorization").split(" ")[1];

        // 删除 token 以注销
        OAuth2AccessToken oAuth2AccessToken = this.tokenStore.readAccessToken(token);
        this.tokenStore.removeAccessToken(oAuth2AccessToken);
        return new ResponseResult<>(ResponseStatus.OK.code(), "用户注销成功！");
    }

    /**
     * 帐号封停
     *
     * @param userId {@link Long} restful风格，封停用户ID
     * @return {@link ResponseResult}
     */
    @PreAuthorize("hasAuthority('ADMIN')")
    @PostMapping("/ban/{userId}")
    public ResponseResult<?> suspend(@PathVariable Long userId) {
        // >0：成功  0：失败
        return this.accountSuspend(userId, BAN_ACCOUNT_FLAG) > 0 ?
                ResponseResult.build(ResponseStatus.OK.code(), ResponseStatus.OK.message()) :
                ResponseResult.build(ResponseStatus.FAIL.code(), ResponseStatus.FAIL.message());
    }

    /**
     * 帐号解封
     *
     * @param userId {@link Long} restful风格，解封用户ID
     * @return {@link ResponseResult}
     */
    @PreAuthorize("hasAuthority('ADMIN')")
    @PostMapping("/unban/{userId}")
    public ResponseResult<?> unSuspend(@PathVariable Long userId) {
        // >0：成功  0：失败
        return this.accountSuspend(userId, UNBAN_ACCOUNT_FLAG) > 0 ?
                ResponseResult.build(ResponseStatus.OK.code(), ResponseStatus.OK.message()) :
                ResponseResult.build(ResponseStatus.FAIL.code(), ResponseStatus.FAIL.message());
    }

    /**
     * 后台：用户基本信息（用户名、头像）
     *
     * @return {@link ResponseResult}
     */
    @PreAuthorize("hasAuthority('BACK')")
    @GetMapping("/back/info")
    public ResponseResult<?> backInfo() throws Exception {
        // 获取个人信息
        LoginInfo loginInfo = this.getInfo();
        if (loginInfo == null) {
            // 熔断
            throw new BusinessException(ResponseStatus.BREAKING);
        }
        return ResponseResult.ok(loginInfo);
    }

    /**
     * 前台：用户基本信息（用户名、头像）
     *
     * @return {@link ResponseResult}
     */
    @PreAuthorize("hasAuthority('USER')")
    @GetMapping("/info")
    public ResponseResult<?> frontInfo() throws Exception {
        // 获取个人信息
        LoginInfo loginInfo = this.getInfo();
        if (loginInfo == null) {
            // 熔断
            throw new BusinessException(ResponseStatus.BREAKING);
        }
        return ResponseResult.ok(loginInfo);
    }

    /**
     * 帐号封停/解封，0封停，1解封
     *
     * @param userId {@link Long} 封停用户ID
     * @param flag   {@link Integer} 0封停，1解封
     * @return {@link Integer}  1：成功  0：失败
     */
    private int accountSuspend(Long userId, Integer flag) {
        // 1、获取用户对象
        TbUser tbUser = this.providerTbUserService.get(userId);
        if (tbUser == null) {
            throw new BusinessException(ResponseStatus.ACCOUNT_NOT_EXIST);
        }

        // 2、判断操作对象是否为本身，即不能封停/解封自己
        if (tbUser.getUsername().equals(this.getAuthenticationName())) {
            throw new BusinessException(ResponseStatus.CANNOT_HANDLE_YOUSELF);
        }

        // 3、封停删除 token，解封则跳过该步骤
        if (flag.equals(BAN_ACCOUNT_FLAG)) {
            Collection<OAuth2AccessToken> oAuth2AccessTokens =
                    this.tokenStore.findTokensByClientIdAndUserName(this.oauth2ClientId,
                            tbUser.getUsername());
            oAuth2AccessTokens.forEach(oAuth2AccessToken -> {
                this.tokenStore.removeAccessToken(oAuth2AccessToken);
            });
        }

        // 4、更新 status 字段
        // 封装 TbUser ，只需要 ID 和 Status
        TbUser updateTbUser = new TbUser();
        updateTbUser.setId(tbUser.getId());
        // 0封停，1解封
        updateTbUser.setStatus(flag);
        // 1：成功  0：失败
        return this.providerTbUserService.update(updateTbUser);
    }

    /**
     * RocketMQ异步发送用户操作日志
     *
     * @param username 用户名 {@link String}
     * @param request  请求对象 {@link HttpServletRequest}
     */
    private void sendTbUserLog(String username, HttpServletRequest request, String note) {
        TbUser umsAdmin = this.providerTbUserService.get(username);

        if (umsAdmin != null) {
            // 获取请求的用户代理信息
            Browser browser = UserAgentUtils.getBrowser(request);
            String ip = UserAgentUtils.getIpAddr(request);
            String address = UserAgentUtils.getIpInfo(ip).getCity();

            TbUserLog tbUserLog = new TbUserLog();
            tbUserLog.setUserId(umsAdmin.getId());
            tbUserLog.setCreateTime(new Date());
            tbUserLog.setIp(ip);
            tbUserLog.setAddress(address);
            tbUserLog.setUserAgent(browser.getName());
            // 备注
            tbUserLog.setNote(note);

            System.out.println("用户数据：" + tbUserLog);
            // this.messageService.sendTbUserLog(tbUserLog);
            log.info("RocketMQ SUCCESS：RocketMQ异步发送用户操作日志成功，" + tbUserLog);
            return;
        }
        log.error("RocketMQ FAIL：User can't be null");
    }

    /**
     * 获取个人信息
     */
    private LoginInfo getInfo() throws Exception {
        // 获取个人信息
        String jsonString = this.profileFeign.info();
        TbUser tbUser = MapperUtils.json2pojoByTree(jsonString, "data", TbUser.class);

        // 按照熔断器给到的结果，此时 tbUser 为空，我们需要直接将熔断结果返回给客户端
        if (tbUser == null) {
            return null;
        }

        // 正常情况下
        LoginInfo loginInfo = new LoginInfo();
        loginInfo.setName(tbUser.getNickName());
        loginInfo.setAvatar(tbUser.getIcon());

        return loginInfo;
    }

    /**
     * 获取 oAuth2 认证用户名
     *
     * @return 认证用户名
     */
    private String getAuthenticationName() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        // "#"是无密码方式登录标记
        return authentication.getName().startsWith("#") ?
                authentication.getName().substring(1) :
                authentication.getName();
    }
}
